#include "p13.h"
#include <iostream>
#include <algorithm>
#include <cctype>
#include <iterator>
#include <ostream>
#include <string_view>


std::string toAsciiLowerCase(std::string_view sv) {
    std::string lower {};

    std::transform(sv.begin(), sv.end(), std::back_inserter(lower),
        [](unsigned char c){ return static_cast<char>(std::tolower(c)); });

    return lower;
}


constexpr void toAsciiLowerCase(const char input[N], char output[N]) {
    for (size_t i = 0; i < N - 1; ++i) { // N-1 to avoid modifying the null terminator
        output[i] = static_cast<char>(std::tolower(static_cast<unsigned char>(input[i])));
    }
    output[N-1] = '\0'; // Ensure null termination
}


void testToAsciiLowerCaseNew() {
    constexpr char input[N] = "HELLO WORLD!";
    char lower[N];

    toAsciiLowerCase(input, lower);

    std::cout << lower << std::endl;
}


constexpr std::string_view getColorName(Color color) {
    switch (color) {
    case Black: return "Black";
    case Red:   return "Red";
    case Blue:  return "Blue";
    case Green: return "Green";
    case Gray:  return "Gray";
    case Pink:  return "Pink";
    case Cyan:  return "Cyan";
    default:    return "NULL";
    }
}


std::ostream& operator<<(std::ostream&out, Color color) {
    return out << getColorName(color);
}

void testColorStdOut() {
    Color shirt {Black};

    std::cout << "Your shirt color is " << shirt << '\n';
}

constexpr std::string_view getAnimalName(Animal animal) {
    switch (animal) {
    case Animal::cat:       return "cat";
    case Animal::pig:       return "pig";
    case Animal::chicken:   return "chicken";
    case Animal::dog:       return "dog";
    case Animal::duck:      return "duck";
    case Animal::goat:      return "goat";
    default:                return "NULL";
    }
}


void printNumberOfLegs(Animal animal) {
    std::cout << "A " << getAnimalName(animal) << "has ";
    switch (animal) {
    case Animal::chicken:
    case Animal::duck:
        std::cout << 2;
        break;
    case Animal::cat:
    case Animal::pig:
    case Animal::dog:
    case Animal::goat:
        std::cout << 4;
        break;
    default:
        std::cout << "???";
        break;
    }
    std::cout << " legs.\n";
}


void testAnimalLegs() {
    printNumberOfLegs(Animal::cat);
    printNumberOfLegs(Animal::duck);
}


constexpr Fraction calFractionMultippliedRes(Fraction& fracA, Fraction fracB) {
    Fraction res = {0, 1};
    res.numerator = fracA.numerator * fracB.numerator;
    res.denominator = fracA.denominator * fracB.denominator;

    return res;
}


void testHomeWork13_13() {
    Pair<double> p2 {3.4, 5.6};
    std::cout << max(p2) << " is larger\n";
}


constexpr std::string_view getMonsterTypeString(const MonsterType& type) {
    switch (type) {
        case MonsterType::MONSTER_ORGE:
            return "Orge";
        case MonsterType::MONSTER_DRAGON:
            return "Dragon";
        case MonsterType::MONSTER_ORC:
            return "Orc";
        case MonsterType::MONSTER_GIANT_SPIDER:
            return "Giant Spider";
        case MonsterType::MONSTER_SLIME:
            return "Slime";
        default:
            return "Unknown";
    }
}


void printMonster(const Monster& monster) {
    std::cout << getMonsterTypeString(monster.type) <<
        " is named " << monster.name <<
        " and has " << monster.health << " health.\n";
}


void testHomeWorkLast_01() {
    Monster orge { MonsterType::MONSTER_ORGE, "Torg", 145 };
    Monster slime { MonsterType::MONSTER_SLIME, "SB", 24 };

    printMonster(orge);
    printMonster(slime);
}


template <typename T>
Traid(T, T, T) -> Traid<T>;

template <typename T>
void print(const Traid<T>& t) {
    std::cout << '[' << t.first << ", " << t.second << ", " << t.third << ']' << '\n';
}


void testHomeWorkLast_03() {
    Traid t1 { 1, 2, 3 };
    print(t1);

    Traid t2 { 1.1, 2.2, 3.2 };
    print(t2);
}
